home *** CD-ROM | disk | FTP | other *** search
/ STraTOS 1997 April & May / STraTOS 1 - 1997 April & May.iso / CD01 / INTERNET / SITES / LITTLE / P3SRC.ZIP / ATARI / VBUFFER.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-01-18  |  45.3 KB  |  2,066 lines

  1. /****************************************************************************
  2. *                   vbuffer.c
  3. *
  4. *  This module implements functions that implement the vista buffer.
  5. *
  6. *  This module was written by Dieter Bayer [DB].
  7. *
  8. *  from Persistence of Vision(tm) Ray Tracer
  9. *  Copyright 1996 Persistence of Vision Team
  10. *---------------------------------------------------------------------------
  11. *  NOTICE: This source code file is provided so that users may experiment
  12. *  with enhancements to POV-Ray and to port the software to platforms other
  13. *  than those supported by the POV-Ray Team.  There are strict rules under
  14. *  which you are permitted to use this file.  The rules are in the file
  15. *  named POVLEGAL.DOC which should be distributed with this file. If
  16. *  POVLEGAL.DOC is not available or for more info please contact the POV-Ray
  17. *  Team Coordinator by leaving a message in CompuServe's Graphics Developer's
  18. *  Forum.  The latest version of POV-Ray may be found there as well.
  19. *
  20. * This program is based on the popular DKB raytracer version 2.12.
  21. * DKBTrace was originally written by David K. Buck.
  22. * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
  23. *
  24. *****************************************************************************/
  25.  
  26. /****************************************************************************
  27. *
  28. *  Explanation:
  29. *
  30. *    -
  31. *
  32. *  ---
  33. *
  34. *  Mar 1994 : Creation.
  35. *
  36. *****************************************************************************/
  37.  
  38. #include "frame.h"
  39. #include "vector.h"
  40. #include "povproto.h"
  41. #include "bbox.h"
  42. #include "boxes.h"
  43. #include "hfield.h"
  44. #include "lighting.h"
  45. #include "matrices.h"
  46. #include "objects.h"
  47. #include "povray.h"
  48. #include "render.h"
  49. #include "triangle.h"
  50. #include "vbuffer.h"
  51. #include "vlbuffer.h"
  52. #include "userio.h"
  53.  
  54.  
  55.  
  56. /*****************************************************************************
  57. * Local preprocessor defines
  58. ******************************************************************************/
  59.  
  60.  
  61.  
  62. /*****************************************************************************
  63. * Local typedefs
  64. ******************************************************************************/
  65.  
  66.  
  67.  
  68. /*****************************************************************************
  69. * Local variables
  70. ******************************************************************************/
  71.  
  72. static DBL Distance;
  73. static MATRIX WC2VC, WC2VCinv;
  74. static VECTOR gO, gU, gV, gW;
  75.  
  76.  
  77. /* Planes for 3d-clipping. */
  78.  
  79. static VECTOR VIEW_VX1 = {-0.8944271910, 0.0, -0.4472135955};
  80. static VECTOR VIEW_VX2 = { 0.8944271910, 0.0, -0.4472135955};
  81. static VECTOR VIEW_VY1 = {0.0, -0.8944271910, -0.4472135955};
  82. static VECTOR VIEW_VY2 = {0.0,  0.8944271910, -0.4472135955};
  83. static DBL VIEW_DX1 = 0.4472135955;
  84. static DBL VIEW_DX2 = 0.4472135955;
  85. static DBL VIEW_DY1 = 0.4472135955;
  86. static DBL VIEW_DY2 = 0.4472135955;
  87.  
  88. static PROJECT_TREE_NODE *Root_Vista;
  89.  
  90.  
  91.  
  92. /*****************************************************************************
  93. * Static functions
  94. ******************************************************************************/
  95.  
  96. static void init_view_coordinates PARAMS((void));
  97.  
  98. static void project_raw_rectangle PARAMS((PROJECT *Project, VECTOR P1, VECTOR P2, VECTOR P3, VECTOR P4, int *visible));
  99. static void project_raw_triangle PARAMS((PROJECT *Project, VECTOR P1, VECTOR P2, VECTOR P3, int *visible));
  100.  
  101. static void project_bbox PARAMS((PROJECT *Project, VECTOR *P, int *visible));
  102. static void project_bounds PARAMS((PROJECT *Project, BBOX *BBox, int *visible));
  103.  
  104. static void get_perspective_projection PARAMS((OBJECT *Object, PROJECT *Project, int infinite));
  105. static void get_orthographic_projection PARAMS((OBJECT *Object, PROJECT *Project, int infinite));
  106.  
  107. static void project_object PARAMS((OBJECT *Object, PROJECT *Project));
  108.  
  109. static void project_box PARAMS((PROJECT *Project, OBJECT *Object, int *visible));
  110. static void project_hfield PARAMS((PROJECT *Project, OBJECT *Object, int *visible));
  111. static void project_triangle PARAMS((PROJECT *Project, OBJECT *Object, int *visible));
  112. static void project_smooth_triangle PARAMS((PROJECT *Project, OBJECT *Object, int *visible));
  113.  
  114. static void transform_point PARAMS((VECTOR P));
  115.  
  116. static void project_bounding_slab PARAMS((PROJECT *Project, PROJECT_TREE_NODE **Tree, BBOX_TREE *Node));
  117.  
  118. static int intersect_vista_tree PARAMS((RAY *Ray, PROJECT_TREE_NODE *Tree, int x, INTERSECTION *Best_Intersection));
  119.  
  120. static void draw_projection PARAMS((PROJECT *Project, int color, int *BigRed, int *BigBlue));
  121. static void draw_vista PARAMS((PROJECT_TREE_NODE *Tree, int *BigRed, int *BigBlue));
  122.  
  123. static void POV_Std_Display_Plot_Box PARAMS((int x1,int y1,int x2,int y2,
  124.  unsigned int r,unsigned int g,unsigned int b,unsigned int a));
  125.  
  126. /*****************************************************************************
  127. *
  128. * FUNCTION
  129. *
  130. *   Prune_Vista_Tree
  131. *
  132. * INPUT
  133. *
  134. *   y - Current scanline number
  135. *   
  136. * OUTPUT
  137. *   
  138. * RETURNS
  139. *   
  140. * AUTHOR
  141. *
  142. *   Dieter Bayer
  143. *   
  144. * DESCRIPTION
  145. *
  146. *   Prune vista tree, i.e. mark all nodes not on the current line inactive.
  147. *
  148. * CHANGES
  149. *
  150. *   May 1994 : Creation.
  151. *
  152. ******************************************************************************/
  153.  
  154. void Prune_Vista_Tree(y)
  155. int y;
  156. {
  157.   unsigned size;
  158.   unsigned short i;
  159.   PROJECT_TREE_NODE *Node, *Sib;
  160.  
  161.   /* If there's no vista tree then return. */
  162.  
  163.   if (Root_Vista == NULL)
  164.   {
  165.     return;
  166.   }
  167.  
  168.   size = 0;
  169.  
  170.   Increase_Counter(stats[VBuffer_Tests]);
  171.  
  172.   if ((y < Root_Vista->Project.y1) || (y > Root_Vista->Project.y2))
  173.   {
  174.     /* Root doesn't lie on current line --> prune root */
  175.  
  176.     Root_Vista->is_leaf |= PRUNE_TEMPORARY;
  177.   }
  178.   else
  179.   {
  180.     /* Root lies on current line --> unprune root */
  181.  
  182.     Increase_Counter(stats[VBuffer_Tests_Succeeded]);
  183.  
  184.     Root_Vista->is_leaf &= ~PRUNE_TEMPORARY;
  185.  
  186.     Node_Queue->Queue[size++] = Root_Vista;
  187.   }
  188.  
  189.   while (size > 0)
  190.   {
  191.     Node = Node_Queue->Queue[--size];
  192.  
  193.     if (Node->is_leaf & TRUE)
  194.     {
  195.       Increase_Counter(stats[VBuffer_Tests]);
  196.  
  197.       if ((y < Node->Project.y1) || (y > Node->Project.y2))
  198.       {
  199.         /* Leaf doesn't lie on current line --> prune leaf */
  200.  
  201.         Node->is_leaf |= PRUNE_TEMPORARY;
  202.       }
  203.       else
  204.       {
  205.         /* Leaf lies on current line --> unprune leaf */
  206.  
  207.         Increase_Counter(stats[VBuffer_Tests_Succeeded]);
  208.  
  209.         Node->is_leaf &= ~PRUNE_TEMPORARY;
  210.       }
  211.     }
  212.     else
  213.     {
  214.       /* Check siblings of the node */
  215.  
  216.       for (i = 0; i < Node->Entries; i++)
  217.       {
  218.         Sib = Node->Entry[i];
  219.  
  220.         Increase_Counter(stats[VBuffer_Tests]);
  221.  
  222.         if ((y < Sib->Project.y1) || (y > Sib->Project.y2))
  223.         {
  224.           /* Sibling doesn't lie on current line --> prune sibling */
  225.  
  226.           Sib->is_leaf |= PRUNE_TEMPORARY;
  227.         }
  228.         else
  229.         {
  230.           /* Sibling lies on current line --> unprune sibling */
  231.  
  232.           Increase_Counter(stats[VBuffer_Tests_Succeeded]);
  233.  
  234.           Sib->is_leaf &= ~PRUNE_TEMPORARY;
  235.  
  236.           /* Add sibling to list */
  237.  
  238.           /* Reallocate queue if it's too small. */
  239.  
  240.           Reinitialize_VLBuffer_Code();
  241.  
  242.           Node_Queue->Queue[size++] = Sib;
  243.         }
  244.       }
  245.     }
  246.   }
  247. }
  248.  
  249.  
  250.  
  251. /*****************************************************************************
  252. *
  253. * FUNCTION
  254. *
  255. *   Trace_Primary_Ray
  256. *
  257. * INPUT
  258. *
  259. *   Ray    - Current ray
  260. *   Colour - Ray's colour
  261. *   x      - Current x-coordinate
  262. *   
  263. * OUTPUT
  264. *
  265. *   colour
  266. *   
  267. * RETURNS
  268. *   
  269. * AUTHOR
  270. *
  271. *   Dieter Bayer
  272. *   
  273. * DESCRIPTION
  274. *
  275. *   Trace a primary ray using the vista tree.
  276. *
  277. * CHANGES
  278. *
  279. *   May 1994 : Creation.
  280. *
  281. *   Nov 1994 : Rearranged calls to Fog, Ranibow and Skyblend.
  282. *              Added call to Atmosphere for atmospheric effects. [DB]
  283. *
  284. *   Jan 1995 : Set intersection depth to Max_Distance for infinte rays. [DB]
  285. *   Jul 1995 : Added code to support alpha channel. [DB]
  286. *
  287. ******************************************************************************/
  288.  
  289. void Trace_Primary_Ray (Ray, Colour, Weight, x)
  290. RAY *Ray;
  291. COLOUR Colour;
  292. DBL Weight;
  293. int x;
  294. {
  295.   int i, Intersection_Found, all_hollow;
  296.   INTERSECTION Best_Intersection;
  297.  
  298.   COOPERATE_0
  299.   Increase_Counter(stats[Number_Of_Rays]);
  300.  
  301.   /* Transmittance has to be 1 to make alpha channel output to work. [DB] */
  302.  
  303.   Make_ColourA(Colour, 0.0, 0.0, 0.0, 0.0, 1.0);
  304.  
  305.   if ((Trace_Level > Max_Trace_Level) || (Weight < ADC_Bailout))
  306.   {
  307.     if (Weight < ADC_Bailout)
  308.     {
  309.       Increase_Counter(stats[ADC_Saves]);
  310.     }
  311.  
  312.     return;
  313.   }
  314.  
  315.   if (Trace_Level > Highest_Trace_Level)
  316.   {
  317.     Highest_Trace_Level = Trace_Level;
  318.   }
  319.  
  320.   Best_Intersection.Depth = BOUND_HUGE;
  321.  
  322.   /* What objects does this ray intersect? */
  323.  
  324.   Intersection_Found = intersect_vista_tree(Ray, Root_Vista, x, &Best_Intersection);
  325.  
  326.   if (Intersection_Found)
  327.   {
  328.     Determine_Apparent_Colour(&Best_Intersection, Colour, Ray, 1.0);
  329.   }
  330.   else
  331.   {
  332.       /* Infinite ray, set intersection distance. */
  333.  
  334.       Best_Intersection.Depth = Max_Distance;
  335.  
  336.       Do_Infinite_Atmosphere(Ray, Colour);
  337.   }
  338.  
  339.   /* Test if all contained objects are hollow. */
  340.  
  341.   all_hollow = TRUE;
  342.  
  343.   if (Ray->Containing_Index > -1)
  344.   {
  345.     for (i = 0; i <= Ray->Containing_Index; i++)
  346.     {
  347.       if (!Test_Flag(Ray->Containing_Objects[i], HOLLOW_FLAG))
  348.       {
  349.         all_hollow = FALSE;
  350.  
  351.         break;
  352.       }
  353.     }
  354.   }
  355.  
  356.   /* Apply finite atmospheric effects. */
  357.  
  358.   if (all_hollow)
  359.   {
  360.     Do_Finite_Atmosphere(Ray, &Best_Intersection, Colour, FALSE);
  361.   }
  362. }
  363.  
  364.  
  365.  
  366. /*****************************************************************************
  367. *
  368. * FUNCTION
  369. *
  370. *   intersect_vista_tree
  371. *
  372. * INPUT
  373. *
  374. *   Ray               - Primary ray
  375. *   Tree              - Vista tree's top-node
  376. *   x                 - Current x-coordinate
  377. *   Best_Intersection - Intersection found
  378. *   
  379. * OUTPUT
  380. *
  381. *   Best_Intersection
  382. *   
  383. * RETURNS
  384. *   
  385. * AUTHOR
  386. *
  387. *   Dieter Bayer
  388. *   
  389. * DESCRIPTION
  390. *
  391. *   Intersect a PRIMARY ray with the vista tree
  392. *   (tree pruning is used can be primary ray!!!).
  393. *
  394. * CHANGES
  395. *
  396. *   May 1994 : Creation.
  397. *
  398. ******************************************************************************/
  399.  
  400. static int intersect_vista_tree(Ray, Tree, x, Best_Intersection)
  401. RAY *Ray;
  402. PROJECT_TREE_NODE *Tree;
  403. int x;
  404. INTERSECTION *Best_Intersection;
  405. {
  406.   INTERSECTION New_Intersection;
  407.   unsigned short i;
  408.   unsigned size;
  409.   int Found;
  410.   RAYINFO rayinfo;
  411.   DBL key;
  412.   BBOX_TREE *BBox_Node;
  413.   PROJECT_TREE_NODE *Node;
  414.  
  415.   /* If there's no vista tree then return. */
  416.  
  417.   if (Tree == NULL)
  418.   {
  419.     return(FALSE);
  420.   }
  421.  
  422.   /* Start with an empty priority queue */
  423.  
  424.   VLBuffer_Queue->QSize = 0;
  425.  
  426.   Found = FALSE;
  427.  
  428. #ifdef BBOX_EXTRA_STATS
  429.   Increase_Counter(stats[totalQueueResets]);
  430. #endif
  431.  
  432.   /* Descend tree. */
  433.  
  434.   size = 0;
  435.  
  436.   /* Create the direction vectors for this ray */
  437.  
  438.   Create_Rayinfo(Ray, &rayinfo);
  439.  
  440.   /* Fill the priority queue with all possible candidates */
  441.  
  442.   /* Check root */
  443.  
  444.   Increase_Counter(stats[VBuffer_Tests]);
  445.  
  446.   if ((x >= Tree->Project.x1) && (x <= Tree->Project.x2))
  447.   {
  448.     Increase_Counter(stats[VBuffer_Tests_Succeeded]);
  449.  
  450.     Node_Queue->Queue[size++] = Tree;
  451.   }
  452.  
  453.   while (size > 0)
  454.   {
  455.     Tree = Node_Queue->Queue[--size];
  456.  
  457.     switch (Tree->is_leaf)
  458.     {
  459.       case FALSE:
  460.  
  461.         /* Check siblings of the unpruned node in 2d */
  462.  
  463.         for (i = 0; i < Tree->Entries; i++)
  464.         {
  465.           Node = Tree->Entry[i];
  466.  
  467.           /* Check unpruned siblings only */
  468.  
  469.           if (Node->is_leaf < PRUNE_CHECK)
  470.           {
  471.             Increase_Counter(stats[VBuffer_Tests]);
  472.  
  473.             if ((x >= Node->Project.x1) && (x <= Node->Project.x2))
  474.             {
  475.               /* Add node to node queue. */
  476.  
  477.               Increase_Counter(stats[VBuffer_Tests_Succeeded]);
  478.  
  479.               /* Reallocate queue if it's too small. */
  480.  
  481.               Reinitialize_VLBuffer_Code();
  482.  
  483.               Node_Queue->Queue[size++] = Node;
  484.             }
  485.           }
  486.         }
  487.  
  488.     break;
  489.  
  490.       case TRUE:
  491.  
  492.         /* Unpruned leaf --> test object's bounding box in 3d */
  493.  
  494.         Check_And_Enqueue(VLBuffer_Queue,
  495.           ((PROJECT_TREE_LEAF *)Tree)->Node,
  496.           &(((PROJECT_TREE_LEAF *)Tree)->Node->BBox),
  497.           &rayinfo);
  498.  
  499.         break;
  500.  
  501.    /* default:
  502.  
  503.         The node/leaf is pruned and needn't be checked */
  504.  
  505.     }
  506.   }
  507.  
  508.   /* Now test the candidates in the priority queue */
  509.  
  510.   while (VLBuffer_Queue->QSize > 0)
  511.   {
  512.     Priority_Queue_Delete(VLBuffer_Queue, &key, &BBox_Node);
  513.  
  514.     if (key > Best_Intersection->Depth)
  515.       break;
  516.  
  517.     if (Intersection(&New_Intersection, (OBJECT *)BBox_Node->Node, Ray))
  518.     {
  519.       if (New_Intersection.Depth < Best_Intersection->Depth)
  520.       {
  521.         *Best_Intersection = New_Intersection;
  522.         Found = TRUE;
  523.       }
  524.     }
  525.   }
  526.  
  527.   return(Found);
  528. }
  529.  
  530.  
  531.  
  532. /*****************************************************************************
  533. *
  534. * FUNCTION
  535. *
  536. *   project_raw_triangle
  537. *
  538. * INPUT
  539. *
  540. *   Project    - Triangle's projection
  541. *   P1, P2, P3 - Triangle's edges
  542. *   visible    - Flag if triangle is visible
  543. *   
  544. * OUTPUT
  545. *
  546. *   Project, visible
  547. *   
  548. * RETURNS
  549. *   
  550. * AUTHOR
  551. *
  552. *   Dieter Bayer
  553. *   
  554. * DESCRIPTION
  555. *
  556. *   Project a triangle onto the screen.
  557. *
  558. * CHANGES
  559. *
  560. *   May 1994 : Creation.
  561. *
  562. ******************************************************************************/
  563.  
  564. static void project_raw_triangle (Project, P1, P2, P3, visible)
  565. PROJECT *Project;
  566. VECTOR P1, P2, P3;
  567. int *visible;
  568. {
  569.   VECTOR Points[MAX_CLIP_POINTS];
  570.   int i, number;
  571.   int x, y;
  572.   DBL rdiv;
  573.  
  574.   Assign_Vector(Points[0], P1);
  575.   Assign_Vector(Points[1], P2);
  576.   Assign_Vector(Points[2], P3);
  577.  
  578.   number = 3;
  579.  
  580.   /* Clip triangle only if some quick tests say it's necessary.
  581.      Assuming that only a few triangles need clipping this saves some time.
  582.      (I don't need to write fabs(1+P?[Z]) since the tests succeed anyway if
  583.       P?[Z] < -1. Hope the compiler doesn't change the tests' order!) */
  584.  
  585.   if ((P1[Z] < -1.0) || (P2[Z] < -1.0) || (P3[Z] < -1.0) ||
  586.       (fabs(P1[X]) > 0.5*(1.0+P1[Z])) || (fabs(P1[Y]) > 0.5*(1.0+P1[Z])) ||
  587.       (fabs(P2[X]) > 0.5*(1.0+P2[Z])) || (fabs(P2[Y]) > 0.5*(1.0+P2[Z])) ||
  588.       (fabs(P3[X]) > 0.5*(1.0+P3[Z])) || (fabs(P3[Y]) > 0.5*(1.0+P3[Z])))
  589.   {
  590.     Clip_Polygon(Points, &number, VIEW_VX1, VIEW_VX2, VIEW_VY1, VIEW_VY2,
  591.                                   VIEW_DX1, VIEW_DX2, VIEW_DY1, VIEW_DY2);
  592.   }
  593.  
  594.   if (number)
  595.   {
  596.     for (i = 0; i < number; i++)
  597.     {
  598.       if (Points[i][Z] < -1.0 + EPSILON)
  599.       {
  600.         Points[i][X] = Points[i][Y] = 0.0;
  601.       }
  602.       else
  603.       {
  604.         rdiv = (1.0 / (1.0 + Points[i][Z]));
  605.         Points[i][X] *= rdiv;
  606.         Points[i][Y] *= rdiv;
  607. /*
  608.         Points[i][X] /= 1.0 + Points[i][Z];
  609.         Points[i][Y] /= 1.0 + Points[i][Z];
  610. */
  611.       }
  612.  
  613.       x = Frame.Screen_Width/2  + (int)(Frame.Screen_Width  * Points[i][X]);
  614.       y = Frame.Screen_Height/2 - (int)(Frame.Screen_Height * Points[i][Y]);
  615.  
  616.       if (x < Project->x1) Project->x1 = x;
  617.       if (x > Project->x2) Project->x2 = x;
  618.       if (y < Project->y1) Project->y1 = y;
  619.       if (y > Project->y2) Project->y2 = y;
  620.     }
  621.  
  622.     *visible = TRUE;
  623.   }
  624. }
  625.  
  626.  
  627.  
  628. /*****************************************************************************
  629. *
  630. * FUNCTION
  631. *
  632. *   project_raw_rectangle
  633. *
  634. * INPUT
  635. *
  636. *   Project        - Rectangle's projection
  637. *   P1, P2, P3, P4 - Rectangle's edges
  638. *   visible        - Flag if rectangle is visible
  639. *   
  640. * OUTPUT
  641. *
  642. *   Project, visible
  643. *   
  644. * RETURNS
  645. *   
  646. * AUTHOR
  647. *
  648. *   Dieter Bayer
  649. *   
  650. * DESCRIPTION
  651. *
  652. *   Project a rectangle onto the screen.
  653. *
  654. * CHANGES
  655. *
  656. *   May 1994 : Creation.
  657. *
  658. ******************************************************************************/
  659.  
  660. static void project_raw_rectangle(Project, P1, P2, P3, P4, visible)
  661. PROJECT *Project;
  662. VECTOR P1, P2, P3, P4;
  663. int *visible;
  664. {
  665.   VECTOR Points[MAX_CLIP_POINTS];
  666.   int i, number;
  667.   int x, y;
  668.   DBL rdiv;
  669.  
  670.   Assign_Vector(Points[0], P1);
  671.   Assign_Vector(Points[1], P2);
  672.   Assign_Vector(Points[2], P3);
  673.   Assign_Vector(Points[3], P4);
  674.  
  675.   number = 4;
  676.  
  677.   Clip_Polygon(Points, &number, VIEW_VX1, VIEW_VX2, VIEW_VY1, VIEW_VY2,
  678.                                 VIEW_DX1, VIEW_DX2, VIEW_DY1, VIEW_DY2);
  679.  
  680.   if (number)
  681.   {
  682.     for (i = 0; i < number; i++)
  683.     {
  684.       if (Points[i][Z] < -1.0 + EPSILON)
  685.       {
  686.         Points[i][X] = Points[i][Y] = 0.0;
  687.       }
  688.       else
  689.       {
  690.         rdiv = (1.0 / (1.0 + Points[i][Z]));
  691.         Points[i][X] *= rdiv;
  692.         Points[i][Y] *= rdiv;
  693. /*
  694.         Points[i][X] /= 1.0 + Points[i][Z];
  695.         Points[i][Y] /= 1.0 + Points[i][Z];
  696. */
  697.       }
  698.  
  699.       x = Frame.Screen_Width/2  + (int)(Frame.Screen_Width  * Points[i][X]);
  700.       y = Frame.Screen_Height/2 - (int)(Frame.Screen_Height * Points[i][Y]);
  701.  
  702.       if (x < Project->x1) Project->x1 = x;
  703.       if (x > Project->x2) Project->x2 = x;
  704.       if (y < Project->y1) Project->y1 = y;
  705.       if (y > Project->y2) Project->y2 = y;
  706.     }
  707.  
  708.     *visible = TRUE;
  709.   }
  710. }
  711.  
  712.  
  713.  
  714.  
  715. /*****************************************************************************
  716. *
  717. * FUNCTION
  718. *
  719. *   project_bbox
  720. *
  721. * INPUT
  722. *
  723. *   Project - Box's projection
  724. *   P       - Box's edges
  725. *   visible - Flag if box is visible
  726. *   
  727. * OUTPUT
  728. *
  729. *   Project, visible
  730. *   
  731. * RETURNS
  732. *   
  733. * AUTHOR
  734. *
  735. *   Dieter Bayer
  736. *   
  737. * DESCRIPTION
  738. *
  739. *   Project a box onto the screen.
  740. *
  741. * CHANGES
  742. *
  743. *   May 1994 : Creation.
  744. *
  745. ******************************************************************************/
  746.  
  747. static void project_bbox(Project, P, visible)
  748. PROJECT *Project;
  749. VECTOR *P;
  750. int *visible;
  751. {
  752.   int vis, i, x, y;
  753.   PROJECT New;
  754.   DBL rdiv;
  755.  
  756.   New.x1 = MAX_BUFFER_ENTRY;
  757.   New.x2 = MIN_BUFFER_ENTRY;
  758.   New.y1 = MAX_BUFFER_ENTRY;
  759.   New.y2 = MIN_BUFFER_ENTRY;
  760.  
  761.   vis = FALSE;
  762.  
  763.   /* Check if all points lie "in front" of the viewer. */
  764.  
  765.   if ((P[0][Z] > -1.0) && (P[1][Z] > -1.0) && (P[2][Z] > -1.0) && (P[3][Z] > -1.0) &&
  766.       (P[4][Z] > -1.0) && (P[5][Z] > -1.0) && (P[6][Z] > -1.0) && (P[7][Z] > -1.0))
  767.   {
  768.     /* Check if all points lie inside the "viewing pyramid". */
  769.  
  770.     if ((fabs(P[0][X]) <= 0.5*(1.0+P[0][Z])) && (fabs(P[1][X]) <= 0.5*(1.0+P[1][Z])) &&
  771.         (fabs(P[2][X]) <= 0.5*(1.0+P[2][Z])) && (fabs(P[3][X]) <= 0.5*(1.0+P[3][Z])) &&
  772.         (fabs(P[4][X]) <= 0.5*(1.0+P[4][Z])) && (fabs(P[5][X]) <= 0.5*(1.0+P[5][Z])) &&
  773.         (fabs(P[6][X]) <= 0.5*(1.0+P[6][Z])) && (fabs(P[7][X]) <= 0.5*(1.0+P[7][Z])) &&
  774.         (fabs(P[0][Y]) <= 0.5*(1.0+P[0][Z])) && (fabs(P[1][Y]) <= 0.5*(1.0+P[1][Z])) &&
  775.         (fabs(P[2][Y]) <= 0.5*(1.0+P[2][Z])) && (fabs(P[3][Y]) <= 0.5*(1.0+P[3][Z])) &&
  776.         (fabs(P[4][Y]) <= 0.5*(1.0+P[4][Z])) && (fabs(P[5][Y]) <= 0.5*(1.0+P[5][Z])) &&
  777.         (fabs(P[6][Y]) <= 0.5*(1.0+P[6][Z])) && (fabs(P[7][Y]) <= 0.5*(1.0+P[7][Z])))
  778.     {
  779.       /* No clipping is needed. Just project the points. */
  780.  
  781.       vis = TRUE;
  782.  
  783.       for (i = 0; i < 8; i++)
  784.       {
  785.         if (P[i][Z] < -1.0 + EPSILON)
  786.         {
  787.           P[i][X] = P[i][Y] = 0.0;
  788.         }
  789.         else
  790.         {
  791.           rdiv = (1.0 / (1.0 + P[i][Z]));
  792.           P[i][X] *= rdiv;
  793.           P[i][Y] *= rdiv;
  794. /*
  795.           P[i][X] /= 1.0 + P[i][Z];
  796.           P[i][Y] /= 1.0 + P[i][Z];
  797. */
  798.         }
  799.  
  800.         x = Frame.Screen_Width/2  + (int)(Frame.Screen_Width  * P[i][X]);
  801.         y = Frame.Screen_Height/2 - (int)(Frame.Screen_Height * P[i][Y]);
  802.  
  803.         if (x < New.x1) New.x1 = x;
  804.         if (x > New.x2) New.x2 = x;
  805.         if (y < New.y1) New.y1 = y;
  806.         if (y > New.y2) New.y2 = y;
  807.       }
  808.     }
  809.   }
  810.  
  811.   if (!vis)
  812.   {
  813.     project_raw_rectangle(&New, P[0], P[1], P[3], P[2], &vis);
  814.     project_raw_rectangle(&New, P[4], P[5], P[7], P[6], &vis);
  815.     project_raw_rectangle(&New, P[0], P[1], P[5], P[4], &vis);
  816.     project_raw_rectangle(&New, P[2], P[3], P[7], P[6], &vis);
  817.     project_raw_rectangle(&New, P[1], P[3], P[7], P[5], &vis);
  818.     project_raw_rectangle(&New, P[0], P[2], P[6], P[4], &vis);
  819.   }
  820.  
  821.   if (vis)
  822.   {
  823.     if (New.x1 > Project->x1) Project->x1 = New.x1;
  824.     if (New.x2 < Project->x2) Project->x2 = New.x2;
  825.     if (New.y1 > Project->y1) Project->y1 = New.y1;
  826.     if (New.y2 < Project->y2) Project->y2 = New.y2;
  827.     *visible = TRUE;
  828.   }
  829. }
  830.  
  831.  
  832.  
  833. /*****************************************************************************
  834. *
  835. * FUNCTION
  836. *
  837. *   project_bounds
  838. *
  839. * INPUT
  840. *
  841. *   Project - Bounding box's projection
  842. *   BBox    - Bounding box
  843. *   visible - Flag if bounding box is visible
  844. *   
  845. * OUTPUT
  846. *
  847. *   Project, visible
  848. *   
  849. * RETURNS
  850. *   
  851. * AUTHOR
  852. *
  853. *   Dieter Bayer
  854. *   
  855. * DESCRIPTION
  856. *
  857. *   Project a bounding box onto the screen.
  858. *
  859. * CHANGES
  860. *
  861. *   May 1994 : Creation.
  862. *
  863. ******************************************************************************/
  864.  
  865. static void project_bounds(Project, BBox, visible)
  866. PROJECT *Project;
  867. BBOX *BBox;
  868. int *visible;
  869. {
  870.   int i;
  871.   VECTOR P[8];
  872.  
  873.   for (i = 0; i<8; i++)
  874.   {
  875.     Assign_BBox_Vect(P[i], BBox->Lower_Left);
  876.  
  877.     P[i][X] += ((i & 1) ? BBox->Lengths[X] : 0.0);
  878.     P[i][Y] += ((i & 2) ? BBox->Lengths[Y] : 0.0);
  879.     P[i][Z] += ((i & 4) ? BBox->Lengths[Z] : 0.0);
  880.  
  881.     transform_point(P[i]);
  882.   }
  883.  
  884.   project_bbox(Project, P, visible);
  885. }
  886.  
  887.  
  888.  
  889. /*****************************************************************************
  890. *
  891. * FUNCTION
  892. *
  893. *   project_box
  894. *
  895. * INPUT
  896. *
  897. *   Project - Projection
  898. *   Object  - Object
  899. *   visible - Flag if object is visible
  900. *   
  901. * OUTPUT
  902. *
  903. *   Project, visible
  904. *   
  905. * RETURNS
  906. *   
  907. * AUTHOR
  908. *
  909. *   Dieter Bayer
  910. *   
  911. * DESCRIPTION
  912. *
  913. *   Project a box onto the screen.
  914. *
  915. * CHANGES
  916. *
  917. *   May 1994 : Creation.
  918. *
  919. ******************************************************************************/
  920.  
  921. static void project_box(Project, Object, visible)
  922. PROJECT *Project;
  923. OBJECT *Object;
  924. int *visible;
  925. {
  926.   int i;
  927.   VECTOR P[8];
  928.   BOX *box;
  929.  
  930.   box = (BOX *)Object;
  931.  
  932.   for (i = 0; i<8; i++)
  933.   {
  934.     Assign_Vector(P[i], box->bounds[0]);
  935.  
  936.     if (i & 1) P[i][X] = box->bounds[1][X];
  937.     if (i & 2) P[i][Y] = box->bounds[1][Y];
  938.     if (i & 4) P[i][Z] = box->bounds[1][Z];
  939.  
  940.     if (box->Trans != NULL)
  941.       MTransPoint(P[i], P[i], box->Trans);
  942.  
  943.     transform_point(P[i]);
  944.   }
  945.  
  946.   project_bbox(Project, P, visible);
  947. }
  948.  
  949.  
  950.  
  951. /*****************************************************************************
  952. *
  953. * FUNCTION
  954. *
  955. *   project_hfield
  956. *
  957. * INPUT
  958. *
  959. *   Project - Projection
  960. *   Object  - Object
  961. *   visible - Flag if object is visible
  962. *   
  963. * OUTPUT
  964. *
  965. *   Project, visible
  966. *   
  967. * RETURNS
  968. *   
  969. * AUTHOR
  970. *
  971. *   Dieter Bayer
  972. *   
  973. * DESCRIPTION
  974. *
  975. *   Project the bounding box of a height field onto the screen.
  976. *
  977. * CHANGES
  978. *
  979. *   May 1994 : Creation.
  980. *
  981. ******************************************************************************/
  982.  
  983. static void project_hfield(Project, Object, visible)
  984. PROJECT *Project;
  985. OBJECT *Object;
  986. int *visible;
  987. {
  988.   int i;
  989.   VECTOR P[8];
  990.   HFIELD *hfield;
  991.  
  992.   hfield = (HFIELD *)Object;
  993.  
  994.   for (i = 0; i<8; i++)
  995.   {
  996.     Assign_Vector(P[i], hfield->bounding_box->bounds[0]);
  997.  
  998.     if (i & 1) P[i][X] = hfield->bounding_box->bounds[1][X];
  999.     if (i & 2) P[i][Y] = hfield->bounding_box->bounds[1][Y];
  1000.     if (i & 4) P[i][Z] = hfield->bounding_box->bounds[1][Z];
  1001.  
  1002.     if (hfield->Trans != NULL)
  1003.     {
  1004.       MTransPoint(P[i], P[i], hfield->Trans);
  1005.     }
  1006.  
  1007.     transform_point(P[i]);
  1008.   }
  1009.  
  1010.   project_bbox(Project, P, visible);
  1011. }
  1012.  
  1013.  
  1014.  
  1015. /*****************************************************************************
  1016. *
  1017. * FUNCTION
  1018. *
  1019. *   project_triangle
  1020. *
  1021. * INPUT
  1022. *
  1023. *   Project - Projection
  1024. *   Object  - Object
  1025. *   visible - Flag if object is visible
  1026. *   
  1027. * OUTPUT
  1028. *
  1029. *   Project, visible
  1030. *   
  1031. * RETURNS
  1032. *   
  1033. * AUTHOR
  1034. *
  1035. *   Dieter Bayer
  1036. *   
  1037. * DESCRIPTION
  1038. *
  1039. *   Project a triangle onto the screen.
  1040. *
  1041. * CHANGES
  1042. *
  1043. *   May 1994 : Creation.
  1044. *
  1045. ******************************************************************************/
  1046.  
  1047. static void project_triangle(Project, Object, visible)
  1048. PROJECT *Project;
  1049. OBJECT *Object;
  1050. int *visible;
  1051. {
  1052.   int i, vis;
  1053.   VECTOR P[3];
  1054.   PROJECT New;
  1055.  
  1056.   New.x1 = MAX_BUFFER_ENTRY;
  1057.   New.x2 = MIN_BUFFER_ENTRY;
  1058.   New.y1 = MAX_BUFFER_ENTRY;
  1059.   New.y2 = MIN_BUFFER_ENTRY;
  1060.  
  1061.   Assign_Vector(P[0], ((TRIANGLE *)Object)->P1);
  1062.   Assign_Vector(P[1], ((TRIANGLE *)Object)->P2);
  1063.   Assign_Vector(P[2], ((TRIANGLE *)Object)->P3);
  1064.  
  1065.   for (i = 0; i < 3; i++)
  1066.   {
  1067.     transform_point(P[i]);
  1068.   }
  1069.  
  1070.   vis = FALSE;
  1071.  
  1072.   project_raw_triangle(&New, P[0], P[1], P[2], &vis);
  1073.  
  1074.   if (vis)
  1075.   {
  1076.     if (New.x1 > Project->x1) Project->x1 = New.x1;
  1077.     if (New.x2 < Project->x2) Project->x2 = New.x2;
  1078.     if (New.y1 > Project->y1) Project->y1 = New.y1;
  1079.     if (New.y2 < Project->y2) Project->y2 = New.y2;
  1080.     *visible = TRUE;
  1081.   }
  1082. }
  1083.  
  1084.  
  1085.  
  1086. /*****************************************************************************
  1087. *
  1088. * FUNCTION
  1089. *
  1090. *   project_smooth_triangle
  1091. *
  1092. * INPUT
  1093. *
  1094. *   Project - Projection
  1095. *   Object  - Object
  1096. *   visible - Flag if object is visible
  1097. *   
  1098. * OUTPUT
  1099. *
  1100. *   Project, visible
  1101. *   
  1102. * RETURNS
  1103. *   
  1104. * AUTHOR
  1105. *
  1106. *   Dieter Bayer
  1107. *   
  1108. * DESCRIPTION
  1109. *
  1110. *   Project a smooth triangle onto the screen.
  1111. *
  1112. * CHANGES
  1113. *
  1114. *   May 1994 : Creation.
  1115. *
  1116. ******************************************************************************/
  1117.  
  1118. static void project_smooth_triangle(Project, Object, visible)
  1119. PROJECT *Project;
  1120. OBJECT *Object;
  1121. int *visible;
  1122. {
  1123.   int i, vis;
  1124.   VECTOR P[3];
  1125.   PROJECT New;
  1126.  
  1127.   New.x1 = MAX_BUFFER_ENTRY;
  1128.   New.x2 = MIN_BUFFER_ENTRY;
  1129.   New.y1 = MAX_BUFFER_ENTRY;
  1130.   New.y2 = MIN_BUFFER_ENTRY;
  1131.  
  1132.   Assign_Vector(P[0], ((SMOOTH_TRIANGLE *)Object)->P1);
  1133.   Assign_Vector(P[1], ((SMOOTH_TRIANGLE *)Object)->P2);
  1134.   Assign_Vector(P[2], ((SMOOTH_TRIANGLE *)Object)->P3);
  1135.  
  1136.   for (i = 0; i < 3; i++)
  1137.   {
  1138.     transform_point(P[i]);
  1139.   }
  1140.  
  1141.   vis = FALSE;
  1142.  
  1143.   project_raw_triangle(&New, P[0], P[1], P[2], &vis);
  1144.  
  1145.   if (vis)
  1146.   {
  1147.     if (New.x1 > Project->x1) Project->x1 = New.x1;
  1148.     if (New.x2 < Project->x2) Project->x2 = New.x2;
  1149.     if (New.y1 > Project->y1) Project->y1 = New.y1;
  1150.     if (New.y2 < Project->y2) Project->y2 = New.y2;
  1151.     *visible = TRUE;
  1152.   }
  1153. }
  1154.  
  1155.  
  1156.  
  1157. /*****************************************************************************
  1158. *
  1159. * FUNCTION
  1160. *
  1161. *   transform_point
  1162. *
  1163. * INPUT
  1164. *
  1165. *   P - Point to transform
  1166. *   
  1167. * OUTPUT
  1168. *
  1169. *   P
  1170. *   
  1171. * RETURNS
  1172. *   
  1173. * AUTHOR
  1174. *
  1175. *   Dieter Bayer
  1176. *   
  1177. * DESCRIPTION
  1178. *
  1179. *   Transform a point from the world coordinate system to the viewer's
  1180. *   coordinate system.
  1181. *
  1182. * CHANGES
  1183. *
  1184. *   May 1994 : Creation.
  1185. *
  1186. ******************************************************************************/
  1187.  
  1188. static void transform_point(P)
  1189. VECTOR P;
  1190. {
  1191.   DBL x,y,z;
  1192.  
  1193.   x = P[X] - gO[X];
  1194.   y = P[Y] - gO[Y];
  1195.   z = P[Z] - gO[Z];
  1196.  
  1197.   P[X] = gU[X] * x + gU[Y] * y + gU[Z] * z;
  1198.   P[Y] = gV[X] * x + gV[Y] * y + gV[Z] * z;
  1199.   P[Z] = gW[X] * x + gW[Y] * y + gW[Z] * z;
  1200. }
  1201.  
  1202.  
  1203.  
  1204. /*****************************************************************************
  1205. *
  1206. * FUNCTION
  1207. *
  1208. *   Init_View_Coordinates
  1209. *
  1210. * INPUT
  1211. *   
  1212. * OUTPUT
  1213. *   
  1214. * RETURNS
  1215. *   
  1216. * AUTHOR
  1217. *
  1218. *   Dieter Bayer
  1219. *   
  1220. * DESCRIPTION
  1221. *
  1222. *   Init the matrices and vectors used to transform a point from
  1223. *   the world coordinate system to the viewer's coordinate system.
  1224. *
  1225. * CHANGES
  1226. *
  1227. *   May 1994 : Creation.
  1228. *
  1229. ******************************************************************************/
  1230.  
  1231. static void init_view_coordinates()
  1232. {
  1233.   DBL k1, k2, k3, up_length, right_length;
  1234.   MATRIX A, B;
  1235.  
  1236.   Assign_Vector(gU, Frame.Camera->Right);
  1237.   Assign_Vector(gV, Frame.Camera->Up);
  1238.   Assign_Vector(gW, Frame.Camera->Direction);
  1239.  
  1240.   VAdd (gO, Frame.Camera->Location, Frame.Camera->Direction);
  1241.  
  1242.   VNormalize(gU,gU);
  1243.   VNormalize(gV,gV);
  1244.   VNormalize(gW,gW);
  1245.  
  1246.   VDot(k1, gU, gV);
  1247.   VDot(k2, gU, gW);
  1248.   VDot(k3, gV, gW);
  1249.  
  1250.   if ((fabs(k1) > EPSILON) || (fabs(k2) > EPSILON) || (fabs(k3) > EPSILON))
  1251.   {
  1252.     Error("Cannot use non-perpendicular camera vectors with vista buffer.\n");
  1253.   }
  1254.  
  1255.   VLength (Distance, Frame.Camera->Direction);
  1256.  
  1257.   VLength (up_length, Frame.Camera->Up);
  1258.   VLength (right_length, Frame.Camera->Right);
  1259.  
  1260.   VScaleEq (gU, 1.0/right_length);
  1261.   VScaleEq (gV, 1.0/up_length);
  1262.   VScaleEq (gW, 1.0/Distance);
  1263.  
  1264.   A[0][0] = gU[X]; A[0][1] = gU[Y]; A[0][2] = gU[Z]; A[0][3] = 0.0;
  1265.   A[1][0] = gV[X]; A[1][1] = gV[Y]; A[1][2] = gV[Z]; A[1][3] = 0.0;
  1266.   A[2][0] = gW[X]; A[2][1] = gW[Y]; A[2][2] = gW[Z]; A[2][3] = 0.0;
  1267.   A[3][0] = 0.0;  A[3][1] = 0.0;  A[3][2] = 0.0;  A[3][3] = 1.0;
  1268.  
  1269.   B[0][0] = 1.0; B[0][1] = 0.0; B[0][2] = 0.0; B[0][3] = -gO[X];
  1270.   B[1][0] = 0.0; B[1][1] = 1.0; B[1][2] = 0.0; B[1][3] = -gO[Y];
  1271.   B[2][0] = 0.0; B[2][1] = 0.0; B[2][2] = 1.0; B[2][3] = -gO[Z];
  1272.   B[3][0] = 0.0; B[3][1] = 0.0; B[3][2] = 0.0; B[3][3] = 1.0;
  1273.  
  1274.   MTimes(WC2VC, A, B);
  1275.   MInvers(WC2VCinv, WC2VC);
  1276. }
  1277.  
  1278.  
  1279.  
  1280. /*****************************************************************************
  1281. *
  1282. * FUNCTION
  1283. *
  1284. *   get_perspective_projection
  1285. *
  1286. * INPUT
  1287. *
  1288. *   Object   - Object to project
  1289. *   Project  - Projection
  1290. *   infinite - Flag if object is infinite
  1291. *   
  1292. * OUTPUT
  1293. *
  1294. *   Project
  1295. *   
  1296. * RETURNS
  1297. *   
  1298. * AUTHOR
  1299. *
  1300. *   Dieter Bayer
  1301. *   
  1302. * DESCRIPTION
  1303. *
  1304. *   Get the perspective projection of a single object, i.e.
  1305. *   the smallest rectangle enclosing the object's image on the screen.
  1306. *
  1307. * CHANGES
  1308. *
  1309. *   May 1994 : Creation.
  1310. *
  1311. ******************************************************************************/
  1312.  
  1313. static void get_perspective_projection(Object, Project, infinite)
  1314. OBJECT *Object;
  1315. PROJECT *Project;
  1316. int infinite;
  1317. {
  1318.   int visible;
  1319.   METHODS *Methods;
  1320.  
  1321.   visible = FALSE;
  1322.  
  1323.   Methods = Object->Methods;
  1324.  
  1325.   /* If the object is infinite, there's no sense of projecting */
  1326.  
  1327.   if (!infinite)
  1328.   {
  1329.     if ((Methods == &Box_Methods) ||
  1330.         (Methods == &Smooth_Triangle_Methods) ||
  1331.         (Methods == &Triangle_Methods) ||
  1332.         (Methods == &HField_Methods))
  1333.     {
  1334.       if (Methods == &Box_Methods)
  1335.         project_box(Project, Object, &visible);
  1336.  
  1337.       if (Methods == &HField_Methods)
  1338.         project_hfield(Project, Object, &visible);
  1339.  
  1340.       if (Methods == &Smooth_Triangle_Methods)
  1341.         project_smooth_triangle(Project, Object, &visible);
  1342.  
  1343.       if (Methods == &Triangle_Methods)
  1344.         project_triangle(Project, Object, &visible);
  1345.     }
  1346.     else
  1347.     {
  1348.       project_bounds(Project, &Object->BBox, &visible);
  1349.     }
  1350.   }
  1351.  
  1352.   if (visible)
  1353.   {
  1354.     if (opts.Options & ANTIALIAS)
  1355.     {
  1356.       /* Increase the rectangle to make sure that nothing will be missed.
  1357.          For anti-aliased images increase by a larger amount. */
  1358.  
  1359.       Project->x1 = max (0,                     Project->x1 - 2);
  1360.       Project->x2 = min (Frame.Screen_Width-1,  Project->x2 + 2);
  1361.       Project->y1 = max (-1,                    Project->y1 - 2);
  1362.       Project->y2 = min (Frame.Screen_Height-1, Project->y2 + 2);
  1363.     }
  1364.     else
  1365.     {
  1366.       /* Increase the rectangle to make sure that nothing will be missed. */
  1367.  
  1368.       Project->x1 = max (0,                     Project->x1 - 1);
  1369.       Project->x2 = min (Frame.Screen_Width-1,  Project->x2 + 1);
  1370.       Project->y1 = max (0,                     Project->y1 - 1);
  1371.       Project->y2 = min (Frame.Screen_Height-1, Project->y2 + 1);
  1372.     }
  1373.   }
  1374.   else
  1375.   {
  1376.     if (!infinite)
  1377.     {
  1378.       /* Object is invisible (the camera can't see it) */
  1379.  
  1380.       Project->x1 = Project->y1 = MAX_BUFFER_ENTRY;
  1381.       Project->x2 = Project->y2 = MIN_BUFFER_ENTRY;
  1382.     }
  1383.   }
  1384. }
  1385.  
  1386.  
  1387.  
  1388. /*****************************************************************************
  1389. *
  1390. * FUNCTION
  1391. *
  1392. *   get_orthographic_projection
  1393. *
  1394. * INPUT
  1395. *
  1396. *   Object   - Object to project
  1397. *   Project  - Projection
  1398. *   infinite - Flag if object is infinite
  1399. *   
  1400. * OUTPUT
  1401. *
  1402. *   Project
  1403. *   
  1404. * RETURNS
  1405. *   
  1406. * AUTHOR
  1407. *
  1408. *   Dieter Bayer
  1409. *   
  1410. * DESCRIPTION
  1411. *
  1412. *   Get the orthographic projection of a single object, i.e.
  1413. *   the smallest rectangle enclosing the object's image on the screen.
  1414. *
  1415. * CHANGES
  1416. *
  1417. *   May 1994 : Creation.
  1418. *
  1419. ******************************************************************************/
  1420.  
  1421. static void get_orthographic_projection(Object, Project, infinite)
  1422. OBJECT *Object;
  1423. PROJECT *Project;
  1424. int infinite;
  1425. {
  1426.   int visible, i, x, y;
  1427.   VECTOR P[8];
  1428.  
  1429.   visible = FALSE;
  1430.  
  1431.   /* If the object is infinite, there's no sense of projecting */
  1432.  
  1433.   if (!infinite)
  1434.   {
  1435.     /* The following could be done better but since only a minority of all
  1436.        objects in a scene are partially visible I don't think it's worth it. */
  1437.  
  1438.     for (i = 0; i < 8; i++)
  1439.     {
  1440.       Assign_BBox_Vect(P[i], Object->BBox.Lower_Left);
  1441.  
  1442.       P[i][X] += ((i & 1) ? Object->BBox.Lengths[X] : 0.0);
  1443.       P[i][Y] += ((i & 2) ? Object->BBox.Lengths[Y] : 0.0);
  1444.       P[i][Z] += ((i & 4) ? Object->BBox.Lengths[Z] : 0.0);
  1445.  
  1446.       transform_point(P[i]);
  1447.  
  1448.       /* Check if bounding box is visible */
  1449.  
  1450.       if (P[i][Z] >= 0.0) visible = TRUE;
  1451.     }
  1452.  
  1453.     /* Now get the projection */
  1454.  
  1455.     if (visible)
  1456.     {
  1457.       Project->x1 = Project->y1 = MAX_BUFFER_ENTRY;
  1458.       Project->x2 = Project->y2 = MIN_BUFFER_ENTRY;
  1459.  
  1460.       for (i = 0; i < 8; i++)
  1461.       {
  1462.         /* The visible area is -0.5...+0.5/-0.5...+0.5 */
  1463.  
  1464.         if (P[i][X] < -0.5) P[i][X] = -0.5;
  1465.         if (P[i][X] >  0.5) P[i][X] =  0.5;
  1466.         if (P[i][Y] < -0.5) P[i][Y] = -0.5;
  1467.         if (P[i][Y] >  0.5) P[i][Y] =  0.5;
  1468.  
  1469.         x = Frame.Screen_Width/2  + (int)(Frame.Screen_Width  * P[i][X]);
  1470.         y = Frame.Screen_Height/2 - (int)(Frame.Screen_Height * P[i][Y]);
  1471.  
  1472.         if (x < Project->x1) Project->x1 = x;
  1473.         if (x > Project->x2) Project->x2 = x;
  1474.         if (y < Project->y1) Project->y1 = y;
  1475.         if (y > Project->y2) Project->y2 = y;
  1476.       }
  1477.     }
  1478.   }
  1479.  
  1480.   if (visible)
  1481.   {
  1482.     if (opts.Options & ANTIALIAS)
  1483.     {
  1484.       /* Increase the rectangle to make sure that nothing will be missed.
  1485.          For anti-aliased images decrease the lower borders. */
  1486.  
  1487.       Project->x1 = max (0,                     Project->x1 - 2);
  1488.       Project->x2 = min (Frame.Screen_Width-1,  Project->x2 + 1);
  1489.       Project->y1 = max (-1,                    Project->y1 - 2);
  1490.       Project->y2 = min (Frame.Screen_Height-1, Project->y2 + 1);
  1491.     }
  1492.     else
  1493.     {
  1494.       /* Increase the rectangle to make sure that nothing will be missed. */
  1495.  
  1496.       Project->x1 = max (0,                     Project->x1 - 1);
  1497.       Project->x2 = min (Frame.Screen_Width-1,  Project->x2 + 1);
  1498.       Project->y1 = max (0,                     Project->y1 - 1);
  1499.       Project->y2 = min (Frame.Screen_Height-1, Project->y2 + 1);
  1500.     }
  1501.   }
  1502.   else
  1503.   {
  1504.     if (!infinite)
  1505.     {
  1506.       /* Object is invisible (the camera can't see it) */
  1507.  
  1508.       Project->x1 = Project->y1 = MAX_BUFFER_ENTRY;
  1509.       Project->x2 = Project->y2 = MIN_BUFFER_ENTRY;
  1510.     }
  1511.   }
  1512. }
  1513.  
  1514.  
  1515.  
  1516. /*****************************************************************************
  1517. *
  1518. * FUNCTION
  1519. *
  1520. *   project_object
  1521. *
  1522. * INPUT
  1523. *
  1524. *   Object   - Object to project
  1525. *   Project  - Projection
  1526. *   
  1527. * OUTPUT
  1528. *
  1529. *   Project
  1530. *   
  1531. * RETURNS
  1532. *   
  1533. * AUTHOR
  1534. *
  1535. *   Dieter Bayer
  1536. *   
  1537. * DESCRIPTION
  1538. *
  1539. *   Get the projection of a single object depending on the camera
  1540. *   used (perspective/orthographic).
  1541. *
  1542. * CHANGES
  1543. *
  1544. *   May 1994 : Creation.
  1545. *
  1546. ******************************************************************************/
  1547.  
  1548. static void project_object(Object, Project)
  1549. OBJECT *Object;
  1550. PROJECT *Project;
  1551. {
  1552.   int infinite;
  1553.  
  1554.   /* Init project fields, assuming the object is visible! */
  1555.  
  1556.   Project->x1 = Project->y1 = MIN_BUFFER_ENTRY;
  1557.   Project->x2 = Project->y2 = MAX_BUFFER_ENTRY;
  1558.  
  1559.   infinite = Test_Flag(Object, INFINITE_FLAG);
  1560.  
  1561.   switch (Frame.Camera->Type)
  1562.   {
  1563.     case PERSPECTIVE_CAMERA:
  1564.  
  1565.       get_perspective_projection(Object, Project, infinite);
  1566.       break;
  1567.  
  1568.     case ORTHOGRAPHIC_CAMERA:
  1569.  
  1570.       get_orthographic_projection(Object, Project, infinite);
  1571.       break;
  1572.  
  1573.     default:
  1574.  
  1575.       Error("Wrong camera type in project_object().\n");
  1576.       break;
  1577.   }
  1578. }
  1579.  
  1580.  
  1581.  
  1582. /*****************************************************************************
  1583. *
  1584. * FUNCTION
  1585. *
  1586. *   project_bounding_slab
  1587. *
  1588. * INPUT
  1589. *
  1590. *   Project  - Projection
  1591. *   Tree     - Current node/leaf
  1592. *   Object   - Node/leaf in bounding slab hierarchy
  1593. *   
  1594. * OUTPUT
  1595. *
  1596. *   Project, Tree
  1597. *   
  1598. * RETURNS
  1599. *   
  1600. * AUTHOR
  1601. *
  1602. *   Dieter Bayer
  1603. *   
  1604. * DESCRIPTION
  1605. *
  1606. *   Project the bounding slab hierarchy onto the screen and thus create
  1607. *   the vista buffer hierarchy.
  1608. *
  1609. * CHANGES
  1610. *
  1611. *   May 1994 : Creation.
  1612. *
  1613. ******************************************************************************/
  1614.  
  1615. static void project_bounding_slab(Project, Tree, Node)
  1616. PROJECT *Project;
  1617. PROJECT_TREE_NODE **Tree;
  1618. BBOX_TREE *Node;
  1619. {
  1620.   short int i;
  1621.   PROJECT Temp;
  1622.   PROJECT_TREE_LEAF *Leaf;
  1623.   PROJECT_TREE_NODE New;
  1624.  
  1625.   if (Node->Entries)
  1626.   {
  1627.     /* Current object is a bounding object, i.e. a node in the slab tree. */
  1628.  
  1629.     /* First, init new entry. */
  1630.  
  1631.     New.Entries = 0;
  1632.  
  1633.     New.Node = Node;
  1634.  
  1635.     New.Project.x1 = New.Project.y1 = MAX_BUFFER_ENTRY;
  1636.     New.Project.x2 = New.Project.y2 = MIN_BUFFER_ENTRY;
  1637.  
  1638.     /* Allocate temporary memory for node/leaf entries. */
  1639.  
  1640.     New.Entry = (PROJECT_TREE_NODE **)POV_MALLOC(Node->Entries*sizeof(PROJECT_TREE_NODE *), "temporary tree entry");
  1641.  
  1642.     /* This is no leaf, it's a node. */
  1643.  
  1644.     New.is_leaf = FALSE;
  1645.  
  1646.     /* Second, get new entry, i.e. project node's entries. */
  1647.  
  1648.     for (i = 0; i < Node->Entries; i++)
  1649.     {
  1650.       New.Entry[i] = NULL;
  1651.  
  1652.       project_bounding_slab(&Temp, &New.Entry[New.Entries], Node->Node[i]);
  1653.  
  1654.       /* Use only visible entries. */
  1655.  
  1656.       if (New.Entry[New.Entries] != NULL)
  1657.       {
  1658.         New.Project.x1 = min(New.Project.x1, Temp.x1);
  1659.         New.Project.x2 = max(New.Project.x2, Temp.x2);
  1660.         New.Project.y1 = min(New.Project.y1, Temp.y1);
  1661.         New.Project.y2 = max(New.Project.y2, Temp.y2);
  1662.  
  1663.         New.Entries++;
  1664.       }
  1665.     }
  1666.  
  1667.     /* If there are any visible entries, we'll use them. */
  1668.  
  1669.     if (New.Entries > 0)
  1670.     {
  1671.       /* If there's only one entry, we won't need a new node. */
  1672.  
  1673.       if (New.Entries == 1)
  1674.       {
  1675.         *Tree    = New.Entry[0];
  1676.         *Project = New.Project;
  1677.       }
  1678.       else
  1679.       {
  1680.         /* Allocate memory for new node in the vista tree. */
  1681.  
  1682.         *Tree = (PROJECT_TREE_NODE *)POV_MALLOC(sizeof(PROJECT_TREE_NODE), "vista tree node");
  1683.  
  1684.         **Tree = New;
  1685.  
  1686.         /* Allocate memory for node/leaf entries. */
  1687.  
  1688.         (*Tree)->Entry = (PROJECT_TREE_NODE **)POV_MALLOC(New.Entries*sizeof(PROJECT_TREE_NODE *), "vista tree node");
  1689.  
  1690.         memcpy((*Tree)->Entry, New.Entry, New.Entries*sizeof(PROJECT_TREE_NODE *));
  1691.  
  1692.         *Project = New.Project;
  1693.       }
  1694.     }
  1695.  
  1696.     /* Get rid of temporary node/leaf entries. */
  1697.  
  1698.     POV_FREE(New.Entry);
  1699.   }
  1700.   else
  1701.   {
  1702.     COOPERATE_0
  1703.  
  1704.     /* Current object is a normal object, i.e. a leaf in the slab tree. */
  1705.  
  1706.     /* Get object's projection. */
  1707.  
  1708.     project_object((OBJECT *)Node->Node, Project);
  1709.  
  1710.     /* Is the object visible? */
  1711.  
  1712.     if ((Project->x1 <= Project->x2) && (Project->y1 <= Project->y2))
  1713.     {
  1714.       /* Allocate memory for new leaf in the vista tree.  */
  1715.  
  1716.       *Tree = (PROJECT_TREE_NODE *)POV_MALLOC(sizeof(PROJECT_TREE_LEAF), "vista tree leaf");
  1717.  
  1718.       /* Init new leaf. */
  1719.  
  1720.       Leaf = (PROJECT_TREE_LEAF *)(*Tree);
  1721.  
  1722.       Leaf->Node = Node;
  1723.  
  1724.       Leaf->Project = *Project;
  1725.  
  1726.       /* Yes, this is a leaf. */
  1727.  
  1728.       Leaf->is_leaf = TRUE;
  1729.     }
  1730.   }
  1731. }
  1732.  
  1733.  
  1734.  
  1735. /*****************************************************************************
  1736. *
  1737. * FUNCTION
  1738. *
  1739. *   Build_Vista_Buffer
  1740. *
  1741. * INPUT
  1742. *   
  1743. * OUTPUT
  1744. *   
  1745. * RETURNS
  1746. *   
  1747. * AUTHOR
  1748. *
  1749. *   Dieter Bayer
  1750. *   
  1751. * DESCRIPTION
  1752. *
  1753. *   Build the vista tree, i.e. the 2d representation of the bounding slab
  1754. *   hierarchy in image space.
  1755. *
  1756. *   This only works for perspective and orthographic cameras.
  1757. *
  1758. * CHANGES
  1759. *
  1760. *   May 1994 : Creation.
  1761. *
  1762. ******************************************************************************/
  1763.  
  1764. void Build_Vista_Buffer()
  1765. {
  1766.   PROJECT Project;
  1767.  
  1768.   Root_Vista = NULL;
  1769.  
  1770.   /* Check if vista buffer can be used. */
  1771.  
  1772.   if ((!opts.Use_Slabs) ||
  1773.       (Frame.Camera->Tnormal != NULL) ||
  1774.       ((Frame.Camera->Type != PERSPECTIVE_CAMERA) && (Frame.Camera->Type != ORTHOGRAPHIC_CAMERA)) ||
  1775.       ((Frame.Camera->Aperture != 0.0) && (Frame.Camera->Blur_Samples > 0)))
  1776.   {
  1777.     opts.Options &= ~USE_VISTA_BUFFER;
  1778.   }
  1779.  
  1780.   if (opts.Options & USE_VISTA_BUFFER)
  1781.   {
  1782.     Status_Info("\nCreating vista buffer.");
  1783.  
  1784.     init_view_coordinates();
  1785.  
  1786.     project_bounding_slab(&Project, &Root_Vista, Root_Object);
  1787.   }
  1788. }
  1789.  
  1790.  
  1791.  
  1792. /*****************************************************************************
  1793. *
  1794. * FUNCTION
  1795. *
  1796. *   Destroy_Vista_Buffer
  1797. *
  1798. * INPUT
  1799. *   
  1800. * OUTPUT
  1801. *   
  1802. * RETURNS
  1803. *   
  1804. * AUTHOR
  1805. *
  1806. *   Dieter Bayer
  1807. *   
  1808. * DESCRIPTION
  1809. *
  1810. *   Destroy the vista tree.
  1811. *
  1812. * CHANGES
  1813. *
  1814. *   Sep 1994 : Creation.
  1815. *
  1816. ******************************************************************************/
  1817.  
  1818. void Destroy_Vista_Buffer()
  1819. {
  1820.   if ((opts.Options & USE_VISTA_BUFFER) && (Root_Vista != NULL))
  1821.   {
  1822.     Destroy_Project_Tree(Root_Vista);
  1823.  
  1824.     Root_Vista = NULL;
  1825.   }
  1826. }
  1827.  
  1828.  
  1829.  
  1830. /*****************************************************************************
  1831. *
  1832. * FUNCTION
  1833. *
  1834. *   draw_projection
  1835. *
  1836. * INPUT
  1837. *
  1838. *   Project - projection to draw
  1839. *   color   - Color to be used
  1840. *   
  1841. * OUTPUT
  1842. *   
  1843. * RETURNS
  1844. *   
  1845. * AUTHOR
  1846. *
  1847. *   Dieter Bayer
  1848. *   
  1849. * DESCRIPTION
  1850. *
  1851. *   Draws a projection in the specified color.
  1852. *
  1853. * CHANGES
  1854. *
  1855. *   May 1994 : Creation.
  1856. *
  1857. ******************************************************************************/
  1858.  
  1859. static void draw_projection(Project, color, BigRed, BigBlue)
  1860. PROJECT *Project;
  1861. int color, *BigRed, *BigBlue;
  1862. {
  1863.   int x1, x2, y1, y2, draw_it;
  1864.   unsigned char r, g, b;
  1865.   unsigned char a=255;
  1866.  
  1867.   switch (color)
  1868.   {
  1869.     case RED   : r = 255; g = b = 0; break;
  1870.     case GREEN : g = 255; r = b = 0; break;
  1871.     case BLUE  : b = 255; r = g = 0; break;
  1872.     default    : r = g = b = 255;
  1873.   }
  1874.  
  1875.   x1 = Project->x1;
  1876.   x2 = Project->x2;
  1877.   y1 = Project->y1;
  1878.   y2 = Project->y2;
  1879.  
  1880.   if ((x1 <= x2) && (y1 <= y2))
  1881.   {
  1882.     if (x1 < 0) x1 = 0;
  1883.     if (x2 < 0) x2 = 0;
  1884.     if (y1 < 0) y1 = 0;
  1885.     if (y2 < 0) y2 = 0;
  1886.  
  1887.     if (x1 >= Frame.Screen_Width)  x1 = Frame.Screen_Width - 1;
  1888.     if (x2 >= Frame.Screen_Width)  x2 = Frame.Screen_Width - 1;
  1889.     if (y1 >= Frame.Screen_Height) y1 = Frame.Screen_Height - 1;
  1890.     if (y2 >= Frame.Screen_Height) y2 = Frame.Screen_Height - 1;
  1891.  
  1892.     /* Check for full-screen rectangle. */
  1893.  
  1894.     draw_it = TRUE;
  1895.  
  1896.     if ((x1 == 0) && (x2 == Frame.Screen_Width - 1) &&
  1897.         (y1 == 0) && (y2 == Frame.Screen_Height - 1))
  1898.     {
  1899.       draw_it = FALSE;
  1900.  
  1901.       switch (color)
  1902.       {
  1903.         case RED   : if (!(*BigRed))  { *BigRed  = draw_it = TRUE; } break;
  1904.         case BLUE  : if (!(*BigBlue)) { *BigBlue = draw_it = TRUE; } break;
  1905.       }
  1906.     }
  1907.  
  1908.     if (draw_it)
  1909.     {
  1910.       POV_DISPLAY_PLOT_BOX(x1,y1,x2,y2,r,g,b,a);
  1911.     }
  1912.   }
  1913. }
  1914.  
  1915.  
  1916.  
  1917. /*****************************************************************************
  1918. *
  1919. * FUNCTION
  1920. *
  1921. *   draw_vista
  1922. *
  1923. * INPUT
  1924. *
  1925. *   Tree - current node/leaf in the vista tree
  1926. *   
  1927. * OUTPUT
  1928. *   
  1929. * RETURNS
  1930. *   
  1931. * AUTHOR
  1932. *
  1933. *   Dieter Bayer
  1934. *   
  1935. * DESCRIPTION
  1936. *
  1937. *   Draws recursively all projections of subnodes in the current node.
  1938. *
  1939. * CHANGES
  1940. *
  1941. *   May 1994 : Creation.
  1942. *
  1943. ******************************************************************************/
  1944.  
  1945. static void draw_vista(Tree, BigRed, BigBlue)
  1946. PROJECT_TREE_NODE *Tree;
  1947. int *BigBlue, *BigRed;
  1948. {
  1949.   unsigned short i;
  1950.   PROJECT_TREE_LEAF *Leaf;
  1951.  
  1952.   if (Tree->is_leaf)
  1953.   {
  1954.     Leaf = (PROJECT_TREE_LEAF *)Tree;
  1955.  
  1956.     COOPERATE_1
  1957.  
  1958.     if (((OBJECT *)Leaf->Node->Node)->Type & COMPOUND_OBJECT)
  1959.     {
  1960.       draw_projection(&Leaf->Project, BLUE, BigRed, BigBlue);
  1961.     }
  1962.     else
  1963.     {
  1964.       draw_projection(&Leaf->Project, RED, BigRed, BigBlue);
  1965.     }
  1966.   }
  1967.   else
  1968.   {
  1969.     for (i = 0; i < Tree->Entries; i++)
  1970.     {
  1971.       draw_vista(Tree->Entry[i], BigRed, BigBlue);
  1972.     }
  1973.   }
  1974.  
  1975.   /* draw bounding object's vista */
  1976.  
  1977. /*
  1978.   draw_projection(&Tree->Project, GREEN);
  1979. */
  1980. }
  1981.  
  1982.  
  1983.  
  1984. /*****************************************************************************
  1985. *
  1986. * FUNCTION
  1987. *
  1988. *   Draw_Vista_Buffer
  1989. *
  1990. * INPUT
  1991. *   
  1992. * OUTPUT
  1993. *   
  1994. * RETURNS
  1995. *   
  1996. * AUTHOR
  1997. *
  1998. *   Dieter Bayer
  1999. *   
  2000. * DESCRIPTION
  2001. *
  2002. *   Draw the vista tree.
  2003. *
  2004. * CHANGES
  2005. *
  2006. *   May 1994 : Creation.
  2007. *
  2008. ******************************************************************************/
  2009.  
  2010. void Draw_Vista_Buffer()
  2011. {
  2012.   int BigRed, BigBlue;
  2013.  
  2014.   BigRed = BigBlue = FALSE;
  2015.  
  2016.   if ((Root_Vista != NULL) && (opts.Options & USE_VISTA_DRAW))
  2017.   {
  2018.     draw_vista(Root_Vista, &BigRed, &BigBlue);
  2019.   }
  2020. }
  2021.  
  2022. /*****************************************************************************
  2023. *
  2024. * FUNCTION
  2025. *
  2026. *   POV_Std_Display_Plot_Box
  2027. *
  2028. * INPUT
  2029. *   
  2030. * OUTPUT
  2031. *   
  2032. * RETURNS
  2033. *   
  2034. * AUTHOR
  2035. *
  2036. *   Chris Young
  2037. *   
  2038. * DESCRIPTION
  2039. *
  2040. *   Generic box drawing routine which may be overriden in POV_DRAW_BOX
  2041. *   by a platform specific routine.
  2042. *
  2043. * CHANGES
  2044. *
  2045. *   Nov 1995 : Creation.
  2046. *
  2047. ******************************************************************************/
  2048. static void POV_Std_Display_Plot_Box(x1,y1,x2,y2,r,g,b,a)
  2049.   int x1,y1,x2,y2;
  2050.   unsigned int r,g,b,a;
  2051.   {
  2052.      int x,y;
  2053.    
  2054.      for (x = x1; x <= x2; x++)
  2055.      {
  2056.        POV_DISPLAY_PLOT(x, y1, r, g, b, a);
  2057.        POV_DISPLAY_PLOT(x, y2, r, g, b, a);
  2058.      }
  2059.  
  2060.      for (y = y1; y <= y2; y++)
  2061.      {
  2062.        POV_DISPLAY_PLOT(x1, y, r, g, b, a);
  2063.        POV_DISPLAY_PLOT(x2, y, r, g, b, a);
  2064.      }
  2065.   }
  2066.